<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="frPcB" id="frPcB"><span data-lake-id="ub633f134" id="ub633f134">典型回答</span></h1>
  <h2 data-lake-id="TWMnM" id="TWMnM"><span data-lake-id="u9eb8c895" id="u9eb8c895">覆盖索引</span></h2>
  <p data-lake-id="u65ebb658" id="u65ebb658"><br></p>
  <p data-lake-id="uea0ce27a" id="uea0ce27a"><span data-lake-id="uf04ddb38" id="uf04ddb38">覆盖索引（covering index）指一个查询语句的执行只用从索引中就能够取得，不必从数据表中读取。也可以称之为实现了索引覆盖。 </span></p>
  <p data-lake-id="uf16a0805" id="uf16a0805"><span data-lake-id="ubb293250" id="ubb293250">​</span><br></p>
  <p data-lake-id="u2e6d353b" id="u2e6d353b"><span data-lake-id="u8b0aeeed" id="u8b0aeeed">当一条查询语句符合覆盖索引条件时，MySQL只需要通过索引就可以返回查询所需要的数据，这样避免了查到索引后再返回表操作，减少I/O提高效率。 </span></p>
  <p data-lake-id="u8e8ec0aa" id="u8e8ec0aa"><span data-lake-id="u3e5afe67" id="u3e5afe67">​</span><br></p>
  <p data-lake-id="u24f0760e" id="u24f0760e"><span data-lake-id="u1dd28352" id="u1dd28352">如，表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。</span></p>
  <p data-lake-id="u9d4afcce" id="u9d4afcce"><span data-lake-id="u1f3a0a53" id="u1f3a0a53">​</span><br></p>
  <p data-lake-id="ue507c580" id="ue507c580"><span data-lake-id="ub34600fa" id="ub34600fa">当我们通过SQL语句：</span></p>
  <p data-lake-id="ufc380f11" id="ufc380f11"><span data-lake-id="u228af320" id="u228af320">​</span><br></p>
  <p data-lake-id="u00dd2b2c" id="u00dd2b2c"><code data-lake-id="udcdb9d45" id="udcdb9d45"><span data-lake-id="ub58e992a" id="ub58e992a">select key2 from covering_index_sample where key1 = ‘keytest’;</span></code></p>
  <p data-lake-id="ub91ab782" id="ub91ab782"><span data-lake-id="u7ddb6e6e" id="u7ddb6e6e">​</span><br></p>
  <p data-lake-id="u00f4ba8a" id="u00f4ba8a"><span data-lake-id="u007776c1" id="u007776c1">的时候，就可以通过覆盖索引查询，无需回表。</span></p>
  <p data-lake-id="ue12c9a69" id="ue12c9a69"><span data-lake-id="ud7b57c34" id="ud7b57c34">​</span><br></p>
  <p data-lake-id="uafaa1fc7" id="uafaa1fc7"><span data-lake-id="u2b4d12e8" id="u2b4d12e8">但是以下SQL，因为不符合最左前缀匹配，虽然是索引覆盖，但是也无法用到索引（会扫描索引树）：</span></p>
  <p data-lake-id="u1c80f044" id="u1c80f044"><span data-lake-id="u194fdc8a" id="u194fdc8a">​</span><br></p>
  <p data-lake-id="u9a1c44f8" id="u9a1c44f8"><code data-lake-id="u62ee2bcc" id="u62ee2bcc"><span data-lake-id="ua7ecffb7" id="ua7ecffb7">select key1 from covering_index_sample where key2 = ‘keytest’;</span></code></p>
  <p data-lake-id="u96d41804" id="u96d41804"><br></p>
  <p data-lake-id="u9717dbed" id="u9717dbed"><span data-lake-id="uf9288399" id="uf9288399">但是如果SQL中查询的信息不包含在联合索引中，那么就不会走索引覆盖。如：</span></p>
  <p data-lake-id="u6fe34cc4" id="u6fe34cc4"><span data-lake-id="uf84f31c8" id="uf84f31c8">​</span><br></p>
  <p data-lake-id="ued921c89" id="ued921c89"><code data-lake-id="u4ef46b39" id="u4ef46b39"><span data-lake-id="u4dab85a4" id="u4dab85a4">select key2,key3 from covering_index_sample where key1 = ‘keytest’;</span></code></p>
  <p data-lake-id="u378c68f2" id="u378c68f2"><span data-lake-id="udae51ad1" id="udae51ad1">​</span><br></p>
  <h2 data-lake-id="HdU4Y" id="HdU4Y"><span data-lake-id="u7f97471a" id="u7f97471a">索引下推</span></h2>
  <p data-lake-id="uffb9989e" id="uffb9989e"><br></p>
  <p data-lake-id="uce55e504" id="uce55e504"><span data-lake-id="u5e710ff9" id="u5e710ff9">索引下推是 MySQL 5.6引入了一种优化技术，默认开启，使用SET optimizer_switch = ‘index_condition_pushdown=off’;可以将其关闭。</span></p>
  <p data-lake-id="u7805fe16" id="u7805fe16"><span data-lake-id="ue4f19654" id="ue4f19654">​</span><br></p>
  <p data-lake-id="ub06fa19e" id="ub06fa19e"><span data-lake-id="u00d627d1" id="u00d627d1">官方文档中给的例子和解释如下： people表中（zipcode，lastname，firstname）构成一个索引</span></p>
  <p data-lake-id="u703d80a5" id="u703d80a5"><span data-lake-id="uc0eb4c60" id="uc0eb4c60">SELECT * FROM people WHERE zipcode=’95054′ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;</span></p>
  <p data-lake-id="u5b3e0a99" id="u5b3e0a99"><span data-lake-id="u295c0730" id="u295c0730">​</span><br></p>
  <p data-lake-id="ue660f364" id="ue660f364"><span data-lake-id="ud8396e2c" id="ud8396e2c">如果没有使用索引下推技术，则MySQL会通过zipcode=’95054’从存储引擎中查询对应的数据，返回到MySQL服务端，然后MySQL服务端基于lastname LIKE ‘%etrunia%’和address LIKE ‘%Main Street%’来判断数据是否符合条件。 </span></p>
  <p data-lake-id="u3c324d7c" id="u3c324d7c"><span data-lake-id="uce0f7090" id="uce0f7090">​</span><br></p>
  <p data-lake-id="u5f6ed3ed" id="u5f6ed3ed"><span data-lake-id="u8c7beff0" id="u8c7beff0">如果使用了索引下推技术，则MYSQL首先会返回符合zipcode=’95054’的索引，然后根据lastname LIKE ‘%etrunia%’来判断索引是否符合条件。</span></p>
  <p data-lake-id="u8c18ce46" id="u8c18ce46"><span data-lake-id="u0c642ba7" id="u0c642ba7">​</span><br></p>
  <p data-lake-id="u0dd5b519" id="u0dd5b519"><span data-lake-id="u2a62834f" id="u2a62834f">如果符合条件，则根据该索引来定位对应的数据，如果不符合，则直接reject掉。 有了索引下推优化，可以在有like条件查询的情况下，减少回表次数。</span></p>
  <p data-lake-id="uc7ee6283" id="uc7ee6283"><span data-lake-id="u89e73730" id="u89e73730">​</span><br></p>
  <p data-lake-id="uec02d72e" id="uec02d72e"><span data-lake-id="u12099a09" id="u12099a09">当一条SQL使用到索引下推时，explain的执行计划中的extra字段中内容为：Using index condition</span></p>
  <p data-lake-id="u29bd371f" id="u29bd371f"><span data-lake-id="u7ce6b919" id="u7ce6b919">​</span><br></p>
  <p data-lake-id="u08f384bf" id="u08f384bf"><span data-lake-id="u331e83fd" id="u331e83fd">​</span><br></p>
  <h3 data-lake-id="fnxO9" id="fnxO9"><span data-lake-id="u3d5fd261" id="u3d5fd261">索引下推不止like</span></h3>
  <p data-lake-id="u4038eef0" id="u4038eef0"><br></p>
  <p data-lake-id="u1425a062" id="u1425a062"><span data-lake-id="ucc0acd53" id="ucc0acd53">上面的例子中，提到了like，包括MySQL官网中也只提到了like，但是其实不止有Like。</span><strong><span data-lake-id="ub43c3138" id="ub43c3138">因为我认为索引下推其实是解决索引失效带来的效率低的问题的一种手段。</span></strong></p>
  <p data-lake-id="udd9f1838" id="udd9f1838"><span data-lake-id="ue7627606" id="ue7627606"><br><br></span></p>
  <p data-lake-id="u23d15be9" id="u23d15be9"><span data-lake-id="udba81918" id="udba81918">所以当联合索引中，某个非前导列因为索引失效而要进行扫表并回表时，就可以进行索引下推优化了。</span></p>
  <p data-lake-id="u62d1fdeb" id="u62d1fdeb"><strong><span data-lake-id="ucd328e30" id="ucd328e30">​</span></strong><br></p>
  <p data-lake-id="u68710ada" id="u68710ada"><span data-lake-id="ub1026cc9" id="ub1026cc9">如，有a,b联合索引，类型都是varchar，以下SQL也可以用到索引下推：</span></p>
  <p data-lake-id="u031c07e7" id="u031c07e7"><span data-lake-id="ube54b717" id="ube54b717">​</span><br></p>
  <pre lang="java"><code>
select d from t2 where a = "ni" and b = 1; 
</code></pre>
  <p data-lake-id="uf11f2764" id="uf11f2764"><span data-lake-id="ue1877ea9" id="ue1877ea9">​</span><br></p>
  <p data-lake-id="udc7e05a7" id="udc7e05a7"><span data-lake-id="uece95571" id="uece95571">因为b字段因为类型不匹配导致索引失效了，但是通过下推优化其实是可以减少回表的次数的。</span></p>
 </body>
</html>